/**
 * 
 * Praktikum CG WP WS13/14
 * Gruppe: Andreas Rebri(andreas.rebri@haw-hamburg.de)
 * 		   Joschka Schulz(joschka.schulz@haw-hamburg.de)
 * Aufgabe : Aufgabenblatt 6
 * Verwendete Quellen: -
 */
package cg6;

import javax.vecmath.Vector3d;

/**
 * the implementation of the monomial curve
 */
public class MonomialCurve implements ICurve {

	/**
	 * the points of the monomial curve
	 */
	private Vector3d[] points;
	
	/**
	 * A constructor with the grade of the curve
	 * 
	 * @param i the grade of the curve
	 */
	public MonomialCurve(int i) {
		points = new Vector3d[i+1];
	}
	
	/**
	 * A constructor of the grade 3 for the monomial curve
	 * 
	 * @param v1 the first vector of the curve
	 * @param v2 the second vector of the curve
	 * @param v3 the third vector of the curve
	 * @param v4 the fourth vector of the curve
	 */
	public MonomialCurve(Vector3d v1, Vector3d v2, Vector3d v3, Vector3d v4) {
		points = new Vector3d[]{v1,v2,v3,v4};
	}
	
	/**
	 * this method gets the degree of the curve
	 * 
	 * @return the degree of the curve as integer
	 */
	public int getDegree() {
		return points.length-1;
	}
	
	/**
	 * Sets one control point
	 * 
	 * @param i the number of the control point
	 * @param v the vector of the control point
	 */
	public void setControlPoint(int i, Vector3d v) {
		points[i] = v;
	}
	
	@Override
	public Vector3d eval(double t) {		
		double resultX = points[0].x;
		double resultY = points[0].y;
		double resultZ = points[0].z;
		
		for(int i = 1; i < points.length; i++) {
			resultX += points[i].x * Math.pow(t, i);
			resultY += points[i].y * Math.pow(t, i);
			resultZ += points[i].z * Math.pow(t, i);
		}
		
		return new Vector3d(resultX, resultY, resultZ);
	}

	@Override
	public Vector3d derivative(double t) {
		double resultX = 0;
		double resultY = 0;
		double resultZ = 0;
		
		for(int i = 1; i < points.length ; i++) {
			resultX += i * points[i].x * Math.pow(t, i-1);
			resultY += i * points[i].y * Math.pow(t, i-1);
			resultZ += i * points[i].z * Math.pow(t, i-1);
		}
		
		return new Vector3d(resultX, resultY, resultZ);
	}

	/**
	 * This method calculates the control points for the curve, that the curve
	 * interpolates the given interpolation points.
	 *  
	 * u(t) = p0 + tp1 + t^2p2
	 *
	 * c0 = p0
	 * c1 = -3p0 + 4p1 - p2
	 * c2 = 2p2 -4p1 + 2p0
	 * 
	 * @param interpolatePoints the points that are used for the calculation of
	 * the points
	 */
	public void interpolationEval(Vector3d[] interpolatePoints) {
		if(interpolatePoints.length == 2) {	
			setControlPoint(0, interpolatePoints[0]);
			
			Vector3d p1 = new Vector3d(interpolatePoints[1]);
			p1.sub(interpolatePoints[0]);
			setControlPoint(1, p1);
		}else if(interpolatePoints.length == 3) {
			double point1X = (-3*interpolatePoints[0].x) + (4 * interpolatePoints[1].x) - interpolatePoints[2].x;
			double point1Y = (-3*interpolatePoints[0].y) + (4 * interpolatePoints[1].y) - interpolatePoints[2].y;
			double point1Z = (-3*interpolatePoints[0].z) + (4 * interpolatePoints[1].z) - interpolatePoints[2].z;
			
			double point2X = (2*interpolatePoints[2].x) - (4 * interpolatePoints[1].x) + (2*interpolatePoints[0].x);
			double point2Y = (2*interpolatePoints[2].y) - (4 * interpolatePoints[1].y) + (2*interpolatePoints[0].y);
			double point2Z = (2*interpolatePoints[2].z) - (4 * interpolatePoints[1].z) + (2*interpolatePoints[0].z);
			
			setControlPoint(0, interpolatePoints[0]);
			setControlPoint(1, new Vector3d(point1X, point1Y, point1Z));
			setControlPoint(2, new Vector3d(point2X, point2Y, point2Z));
		}
	}
}
